#include <iostream>
#include <unistd.h>
#include <sys/epoll.h>
#include <functional>
#include <string>

#include "sock.hpp"
#include "error.hpp"

namespace Server
{
    static const int defaultPort = 8080;
    static const int size = 128;
    static const int defaultnum = 64;
    static const int defaultvalue = -1;

    using func_t = std::function<std::string(const std::string &)>;

    class epollServer
    {
    public:
        epollServer(func_t func, uint16_t port = defaultPort, int num = defaultnum)
            : _port(port), _listensock(defaultvalue), _num(num), _epfd(defaultvalue), _func(func)
        {
        }
        ~epollServer()
        {
            if (_listensock != defaultvalue)
            {
                close(_listensock);
            }
            if (_erfds)
            {
                delete[] _erfds;
            }
            if (_epfd != defaultvalue)
            {
                close(_epfd);
            }
        }

        void InitServer()
        {
            // 1.创建套接字
            _listensock = Sock::Socket();
            Sock::Bind(_listensock, _port);
            Sock::Listen(_listensock);

            // 2.创建epoll模型
            _epfd = epoll_create(size);
            if (_epfd < 0)
            {
                logMessage(ERROR, "create epoll 模型 error");
                exit(EPOLL_CREATE_ERR);
            }
            // 3.将listensock添加进入epoll中
            struct epoll_event ev;
            ev.events = EPOLLIN;
            ev.data.fd = _listensock;
            epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock, &ev);

            // 申请就绪空间的大小
            _erfds = new struct epoll_event[_num];
            logMessage(NORMAL, "Init epoll success!");
        }

        void Handlerevents(int readyNum)
        {
            logMessage(DEBUG, "Handlerevents begin ...\n");
            for (int i = 0; i < readyNum; i++)
            {
                uint32_t event = _erfds[i].events;
                int sock = _erfds[i].data.fd;

                if (sock == _listensock && (event & EPOLLIN))
                {
                    uint16_t clientPort;
                    std::string clientIP;
                    // 监听套接字就绪
                    int fd = Sock::Accpet(sock, &clientPort, &clientIP);
                    if (fd < 0)
                    {
                        logMessage(NORMAL, "Accept fail ...\n");
                        continue;
                    }
                    // 将fd添加到 epoll 模型中
                    struct epoll_event ev;
                    ev.events = EPOLLIN;
                    ev.data.fd = fd;
                    epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);
                }
                else if (event & EPOLLIN)
                {
                    // 普通事件就绪
                    char buffer[2048];
                    int n = recv(sock, buffer, sizeof(buffer) - 1, 0);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        logMessage(DEBUG, "client#: %s\n", buffer);
                        std::string response = _func(buffer);
                        send(sock, response.c_str(), response.size(), 0);
                    }
                    else if (n == 0)
                    {
                        // 客户端退出  先将sock从epoll中移除，再关闭sock
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                        close(sock);
                        logMessage(NORMAL, "client quit,me too ...\n");
                    }
                    else
                    {
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                        close(sock);
                        logMessage(WARNING, "recv error ...\n");
                    }
                }
            }
        }

        void Start()
        {
            int timeout = -1;
            for (;;)
            {
                int n = epoll_wait(_epfd, _erfds, _num, timeout); // 就绪事件全部存储在 _erfds 中
                switch (n)
                {
                case 0: // 超时
                    logMessage(NORMAL, "time out ...\n");
                    break;
                case -1:
                    logMessage(FATAL, "EPOLL_WAIT EORROR\n");
                    break;
                default:
                    logMessage(NORMAL, "have a event readys\n");
                    Handlerevents(n);
                    break;
                }
            }
        }

    private:
        uint16_t _port;
        int _listensock;
        int _epfd;
        int _num;                   // 就绪事件的空间大小
        struct epoll_event *_erfds; // 就绪事件
        func_t _func;
    };
}